<?php
/**
 * @package contenite
 */

/**
 * @package contenite
 * Base class for application controllers. 
 * Generally used as (controller > app_controller > my_controller) 
 */
class controller {
  var $rendered = FALSE;
  var $layout = 'layout';
  var $action = NULL;
  var $path = NULL;

  var $page_title = '';
  var $title = '';
  
  function __construct() {
    $this->class = preg_replace('/_controller$/', '', get_class($this));
    $this->page_title = ucfirst($this->class);
    set_controller($this);
  }

  function _act($action, $path, $args) {
    $this->action = $action;
    
    $this->page_title .= ' / ' . $this->action;
    
    $this->path = $path;
    $this->args = $args;
    $this->rendered = FALSE;
    $this->scripts = array();
    
    if (method_exists($this, '_pre')) {
      $this->_pre();
    }

    $this->content = $this->$action();
    if (!$this->rendered) {
      $this->content = $this->_render(array(
        $this->class . '_' . $this->action,
        $this->class));
        
      if ($this->content !== FALSE) {
        $this->rendered = TRUE;
      }
      else {
        throw new Exception(sprintf('No template for action %s::%s: %s', 
          $this->class, $this->action, $this->content));
      }
    }
    
    if (isset($this->layout) && $this->layout !== FALSE && !isset($_SERVER['COMMAND_LINE'])) {
      echo $this->_render($this->layout);
    }
    else {
      echo $this->content;
    }
  }
  
  function _render($candidates, $vars = NULL) {
    global $config;

    if ($vars === NULL) {
      $vars = get_object_vars($this);
    }
    extract($vars, EXTR_SKIP);
    
    if (!is_array($candidates)) {
      $candidates = array($candidates);
    }
    
    $dirs = explode(PATH_SEPARATOR, get_include_path());
    $dirs[] = $config['contenite_dir'];
    
    //D error_log('_render: candidates ' . serialize($candidates));
    foreach ($candidates as $candidate) {
      foreach ($dirs as $location) {
        $file =  $location . '/' . $candidate . '.v.php';
        //D error_log('_render: trying ' . $file);
        if (file_exists($file)) {
          ob_start();
          if (isset($_GET['tpldebug']) && $_GET['tpldebug']) echo $file, ":";
          require $file;
          $this->rendered = TRUE;
          //D error_log('_render: ' . $file . ' succeeded.');
          return ob_get_clean();
        }
      }
    }
    throw new Exception(sprintf('No template for action %s::%s. I tried "%s"', 
      $this->class, $this->action, join('", "', $candidates)));
  }
  
  function _section_fields($section) {
    static $sections;
    
    $class = get_class($this->data);
    if (!isset($sections[$class])) {
      foreach ($this->data->_fields as $name => $field) {
        $field_section = isset($field['section']) ? $field['section'] : 'all';
        $sections[$class][$field_section][] = $name;
      }
    }
    return $sections[$class][$section];
  }

  /**
   * Helper
   */
  function _form($section = 'all', $attr = array()) {
    $output = array();
    
    if (isset($attr['_pre'])) {
      $output[] = $attr['_pre'];
      unset($attr['_pre']);
    }
    
    $output[] = '<input name="type" type="hidden" value="' . get_class($this->data) . '" />';
    foreach ($this->_section_fields($section) as $name) {
      $field = $this->data->_fields[$name];
      $field += array('widget' => isset($field['type']) && $field['type'] == 'TEXT' ? 'textarea' : 'text');
      $title = isset($field['title']) 
        ? $field['title']
        : ucfirst($name);
     
      $widget = $field['widget'];
      if (is_array($widget)) {
        $widget_name = array_shift($widget);
      }
      else {
        $widget_name = $widget;
        $widget = array();
      }
      $value = $widget_name == 'password' || !isset($this->data->$name)
        ? '' : addslashes($this->data->$name);
      
      if ($widget_name != 'file' && !$this->data->access($field)) {
        $value = '';
      }
        
      switch ($widget_name) {
        case 'text':
        case 'password':
          $output[] = '<label for="' . $name . '">' . $title . ': '
            . '<input name="' . $name
            . '" class="' . $field['widget']
            . (isset($field['css class']) 
              ? (' ' . $field['css class']) : '')
            . (isset($field['css id']) 
              ? ('" id="' . $field['css id']) : '')
            . '" type="' . $field['widget']
            . '" value="' . $value
            . '" cte:default="' . addslashes(isset($field['default']) ? $field['default'] : '')
            . '" /></label>';
          break;

        case 'hidden':
          $output[] = '<input name="' . $name . '" type="hidden" value="' . $value . '" />';
          break;

        case 'select':
           $output[] = '<label for="' . $name . '">' 
            . $title . ': '
            . '<select name="' . $name
            .'">';
          foreach ($widget[0] as $n => $v) {
            $output[] = '<option value="' . addslashes($n) 
              . ($value == $n ? '" selected="SELECTED' : '')
              . '">' . $v . '</option>';
          }
          $output[] .= '</select></label>';
          break;

        case 'textarea':
          $output[] = '<label for="' . $name . '">' 
            . $title . ': '
            . '<textarea name="' . $name 
            . (isset($field['css id']) 
              ? ('" id="' . $field['css id']) : '')
            . (isset($field['css class']) 
              ? ('" class="' . $field['css class']) : '')
            . '" cte:default="' . addslashes(isset($field['default']) ? $field['default'] : '')
            . '" rows="8">' . $value . '</textarea></label>';
          break;

        case 'fckeditor':
          global $config;
          ob_start();
          require_once $config['root_dir'] . '/fckeditor/fckeditor.php';
          $fck = new FCKeditor($name);
          $fck->BasePath = $config['root'] . '/fckeditor/';
          //$fck->ToolbarSet = 'Aktionen';
          $fck->Value = stripslashes($value);
          $fck->Height = '500px';
          $fck->Create();

          $output[] = '<label for="' . $name . '">' . $title . ': '
            . ob_get_clean() . '</label>';
          break;

        case 'file':
        case 'image':
          if ($this->data->access($field)) {
            $iframe = '<iframe scrolling="no" marginheight="0" marginwidth="0" frameborder="0"'
              . ' src="/cv/upload/' . $name 
              . '" id="f_' . $name . '"></iframe>';          
          }
          else {
            $iframe = '';
          }
          $output[] = '<label class="file" for="' . $name . '">' . $title . ': '
            . '<input id="cte-' . $name
            . '" cte:default="' . addslashes(isset($field['default']) ? $field['default'] : '')
            . '" value="' . $value
            . '" />' . $iframe . '</label>';
          break;
      }

    }
    if (isset($attr['_post'])) {
      $output[] = $attr['_post'];
      unset($attr['_post']);
    }
    return '<form ' . vars($attr) . '>' . join('', $output) . '</form>';  
  }
  
  /**
   * Helper: An entry in a has_many form
   */
  function _harp_entry($name, $item, $attr) {    
    $model = $this->data->_has_many[$name]['model']; // from the cv

    // fields to show in list titles
    $list =& $this->data->_has_many[$name]['list']; // from the cv
    $value = array();
    foreach ($list as $field) {
      $value[] = '<span class="cte-' . $model . '-' . $item['id'] . '-' . $field . '">'
        . $item[$field] . '</span>';
    }
    $item += array('class' => array());

    return '<li cte:id="' . $item['id'] . '" id="cte-' . $model . '-'
      . $item['id'] . '" class="' . join(' ', $item['class']) 
      . '"><a class="up" title="nach oben" href="/slot/up/'
      . $item['id'] . '">&nbsp;</a>'
      . '<a class="down" title="nach unten" href="/slot/down/'
      . $item['id'] . '">&nbsp;</a>'
      . '<a class="del confirm" title="Eintrag löschen" href="/slot/del/'
      . $item['id'] . '">&nbsp;</a>'
      . '<a class="open" cte:section="' . $name . '" title="zum Bearbeiten von ' 
      . $name . ':' . $item['id'] . ' klicken" href="#">' 
      . join(' ', $value) 
      . (!$item['enabled'] ? ' (x)' : '')
      . '</a></li>';
  }

  /**
   * Helper: An entry form in a has_many form
   */
  function _harp_form($name, $item, $attr) {    
    $model = $this->data->_has_many[$name]['model']; // from the cv

    $sub = new controller;
    $sub->data = new $model($item);
    return '<div class="slot-form" id="cte' . $item['id'] . '">' 
      . $sub->_form('all', $attr) . '</div>';
  }

 /**
   * Helper: A form for has_many relationships
   */
  function _harp($name, $attr) {
    $output = array('<p><a class="add" href="/cv/add/' 
      . $name . '">Einen Eintrag hinzufügen</a></p>');
    $output[] = '<ul class="slots">';

    $model = $this->data->_has_many[$name]['model'];
    $n = count($this->data->$name) - 1;
    //D error_log("_harp($name) => #$n");
    foreach ($this->data->$name as $i => $item) {
      $item['class'] = array();
      if ($i == 0) {
        $item['class'][] = 'first';
      }
      if ($i == $n) {
        $item['class'][] = 'last';
      }
      $output[] = $this->_harp_entry($name, $item, $attr);
    }
    $output[] = '</ul>';
    return join('', $output);
  }
}
